package eteam.aps.api;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import eteam.aps.common.component.LoginUserRedisService;
import eteam.aps.common.constant.ArrivalType;
import eteam.aps.common.exceptions.BusinessException;
import eteam.aps.common.helper.Helper;
import eteam.aps.common.helper.JsonPage;
import eteam.aps.config.AppContext;
import eteam.aps.config.RedisHelper;
import eteam.aps.model.entity.*;
import eteam.aps.model.entity.arrival.ArrivalDl;
import eteam.aps.model.entity.arrival.ArrivalRep;
import eteam.aps.model.entity.arrival.ArrivalRepository;
import eteam.aps.model.entity.arrival.ArrivalVouch;
import eteam.aps.model.entity.other.*;
import eteam.aps.model.export.model.InventoryExport;
import eteam.aps.model.export.query.InventoryQuery;
import eteam.aps.model.vo.arrival.ArrivalRepositoryBody;
import eteam.aps.model.vo.sales_order.SaleOrderQueryVo;
import eteam.aps.systeminterface.model.vo.QueryInfoVo;
import eteam.aps.zn.YYConstant;
import eteam.aps.zn.ZNApiConstant;
import org.springframework.http.HttpStatus;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author LiuLei
 */
public class U8Api {

    /**
     * 默认登录 参数
     *
     * @return map 登录参数
     */
    private static Map<String, Object> tokenMap() {
        // 登录默认参数 map对象
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("from_account", ZNApiConstant.USER);
        paramMap.put("app_key", ZNApiConstant.APP_KEY);
        paramMap.put("app_secret", ZNApiConstant.APP_SECRET);
        return paramMap;
    }

    /**
     * 用友接口 接口公共参数
     *
     * @return 参数集
     * @throws Exception 异常
     */
    public static Map<String, Object> pubMap() throws Exception {
        Map<String, Object> paramMap = new HashMap<>(4);
        paramMap.put("from_account", ZNApiConstant.USER);
        paramMap.put("to_account", ZNApiConstant.USER);
        paramMap.put("token", authToken());
        paramMap.put("app_key", ZNApiConstant.APP_KEY);
        paramMap.put("ds_sequence", ZNApiConstant.DS_SEQUENCE);
        return paramMap;
    }

//    /**
//     * 获取 到货单信息
//     *
//     * @param bar 到货单条码
//     * @return 到货单
//     * @throws JsonProcessingException json解析异常
//     */
//    public static ArrivalDl getArrivalVouch(String bar) throws Exception {
//        String response = HttpUtil.get(YYConstant.ARRIVAL_URL, Collections.singletonMap("bar", bar));
//        // 判断请求状态
//        JSONObject arrival = JSONUtil.parseObj(response);
//        // 判断请求状态
//        if (arrival.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, arrival.getStr("msg"));
//        // 请求失败 抛出请求异常信息
//        JSONObject data = arrival.getJSONObject("data");
//        if (data.isEmpty()) return null;
//        return parseArrivalDl(data);
//    }

    /**
     * 获取 到货单信息
     *
     * @param bar 到货单条码
     * @return 到货单
     * @throws JsonProcessingException json解析异常
     */
    public static ArrivalVouch getArrivalVouch(String bar) throws Exception {
        String response = HttpUtil.get(YYConstant.ARRIVAL_URL, Collections.singletonMap("bar", bar));
        // 判断请求状态
        JSONObject arrival = JSONUtil.parseObj(response);
        // 判断请求状态
        if (arrival.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, arrival.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONObject data = arrival.getJSONObject("data");
        if (data.isEmpty()) return null;
        return Helper.JACKSON_OBJECT_MAPPER.readValue(data.toString(), ArrivalVouch.class);
    }

//    /**
//     * 获取 到货单信息集
//     *
//     * @param code 到货单单据
//     * @return 到货单
//     * @throws JsonProcessingException json解析异常
//     */
//    public static List<ArrivalDl> getArrivalVouchList(String code) throws Exception {
//        String response = HttpUtil.get(YYConstant.ARRIVAL_LIST_URL, Collections.singletonMap("code", code));
//        // 判断请求状态
//        JSONObject arrival = JSONUtil.parseObj(response);
//        // 判断请求状态
//        if (arrival.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, arrival.getStr("msg"));
//        // 请求失败 抛出请求异常信息
//        JSONArray data = arrival.getJSONArray("data");
//        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据！");
//        List<ArrivalDl> list = new LinkedList<>();
//        for (Object datum : data) {
//            JSONObject arr = (JSONObject) datum;
//            list.add(parseArrivalDl(arr));
//        }
//        return list;
//    }

    /**
     * 获取 到货单信息集
     *
     * @param code 到货单单据
     * @return 到货单
     * @throws JsonProcessingException json解析异常
     */
    public static List<ArrivalVouch> getArrivalVouchList(String code) throws Exception {
        String response = HttpUtil.get(YYConstant.ARRIVAL_LIST_URL, Collections.singletonMap("code", code));
        // 判断请求状态
        JSONObject arrival = JSONUtil.parseObj(response);
        // 判断请求状态
        if (arrival.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, arrival.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONArray data = arrival.getJSONArray("data");
        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据！");
        List<ArrivalVouch> list = new LinkedList<>();
        for (Object datum : data) {
            JSONObject arr = (JSONObject) datum;
            list.add(Helper.JACKSON_OBJECT_MAPPER.readValue(arr.toString(), ArrivalVouch.class));
        }
        return list;
    }

    /**
     * 解析到货单
     *
     * @param arrivalDl 到货单类型
     * @return
     * @throws Exception
     */
    private static ArrivalDl parseArrivalDl(JSONObject arrivalDl) throws Exception {
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        ArrivalDl dl = new ArrivalDl();
        String fuserid = AppContext.getBean(LoginUserRedisService.class).getUser().getFuserid();
        // 获取默认单
        JSONObject normal = arrivalDl.getJSONObject("normal");
        // 默认单不为空
        if (!normal.isEmpty()) {
            // 解析到货单
            ArrivalVouch arrival = om.readValue(normal.toString(), ArrivalVouch.class);
            // 填充
            Helper.setDefaultAddValue(arrival, fuserid);
            // 设置合并项 默认的就是自己
            arrival.setfMergeBar(arrival.getfBarCode());
            // 设置为默认单
            arrival.setfArrivalType(ArrivalType.DEFAULT);
            // 设置保存和展示项
            List<ArrivalVouch> vouchList = new LinkedList<>();
            vouchList.add(arrival);
            // 填充
            dl.setView(vouchList);
            dl.setSaveList(vouchList);
            // 为默认单就不可能为其他单直接结束函数
            return dl;
        }
        // 非默认单
        JSONObject merge = arrivalDl.getJSONObject("merge");
        // 展示项
        List<ArrivalVouch> viewList = new LinkedList<>();
        // 保存项
        List<ArrivalVouch> saveList = new LinkedList<>();
        // 如果合并项不为空 就设置合并项
        if (!merge.isEmpty()) {
            // 解析到货单
            ArrivalVouch arrival = om.readValue(merge.toString(), ArrivalVouch.class);
            // 填充
            Helper.setDefaultAddValue(arrival, fuserid);
            // 设置为合并单
            arrival.setfArrivalType(ArrivalType.MERGE);
            // 设置保存和展示项
            viewList.add(arrival);
            saveList.add(arrival);
            if (!arrivalDl.isNull("subset")) {
                // 解析差分单
                JSONArray subset = arrivalDl.getJSONArray("subset");
                // 拆分单不为空
                if (!subset.isEmpty()) {
                    // 解析每一条单
                    for (Object set : subset) {
                        // 解析为到货单
                        ArrivalVouch avl = om.readValue(set.toString(), ArrivalVouch.class);
                        // 填充
                        Helper.setDefaultAddValue(avl, fuserid);
                        // 设置为拆分单
                        avl.setfArrivalType(ArrivalType.SUBSET);
                        // 设置合并单号
                        avl.setfMergeBar(arrival.getfBarCode());
                        // 拆分单不需要质检 应为是合并单绑定的额 需要设置数量
                        avl.setfFinStockQuantity(avl.getfIQuantity());
                        // 保存单追加
                        saveList.add(avl);
                    }
                }
            }
        }
        dl.setView(viewList);
        dl.setSaveList(saveList);
        return dl;
    }


    /**
     * 到货单详情查询
     *
     * @param dto          单头信息
     * @param arrivalRep   到货单信息
     * @param detailsParam 查询条件
     * @return 到货单单身
     */
    public static List<ArrivalRepositoryBody> getArrivalRepository(ArrivalRepository dto, ArrivalRep arrivalRep, Map<String, Object> detailsParam) {
        String response = HttpUtil.post(YYConstant.ARRIVAL_DETAILS_URL, JSONUtil.toJsonStr(detailsParam));
        // 判断请求状态
        JSONObject arrival = JSONUtil.parseObj(response);
        // 判断请求状态
        if (arrival.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, arrival.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONArray data = arrival.getJSONArray("data");
        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据！");
        List<ArrivalRepositoryBody> list = new ArrayList<>();
        String time;
        Map<String, Object> map = new HashMap<>(4);
        map.put("invCode", arrivalRep.getInvCode());
        map.put("batch", arrivalRep.getBatch());
        map.put("whCode", dto.getcWhCode());
        map.put("free", arrivalRep.getBanBen());
        // 设置时间
        time = U8Api.getCurrentStockDate(map);
        // 查到了时间  就直接设置
        if (Helper.isNotEmpty(time)) {
            if (time.length() > 10) time = time.substring(0, 10);
        } else if (Helper.isEmpty(time) && Helper.isNotEmpty(arrivalRep.getBanBen())) { // 时间不存在 并且自由项不为空 证明上一次查询带上了自由项
            // 移除自由项
            map.remove("free");
            // 查询
            time = U8Api.getCurrentStockDate(map);
            // 如果时间不为空 就重新赋值  否则保持不变
            if (Helper.isNotEmpty(time) && time.length() > 10) time = time.substring(0, 10);
        }
        if (Helper.isEmpty(time)) time = LocalDate.now().toString();
        BigDecimal bg = BigDecimal.ZERO;
        for (Object body : data) {
            JSONObject row = (JSONObject) body;
            ArrivalRepositoryBody repositoryBody = new ArrivalRepositoryBody();
            repositoryBody.setCInvCode(arrivalRep.getInvCode());
            repositoryBody.setITaxRate(BigDecimal.ZERO);
            repositoryBody.setTaxUnitPrice(BigDecimal.ZERO);
            repositoryBody.setISum(BigDecimal.ZERO);
            repositoryBody.setCBatch(arrivalRep.getBatch());
            repositoryBody.setCVarvCode(arrivalRep.getCode());
            repositoryBody.setDMDate(time);
            repositoryBody.setIQuantity(row.getBigDecimal("qty", BigDecimal.ZERO));
            repositoryBody.setCFree1(row.getStr("free", ""));
            repositoryBody.setIPOsID(row.getInt("posId", 0));
            repositoryBody.setIArrsId(row.getInt("autoId", 0));
            bg = bg.add(repositoryBody.getIQuantity());
            list.add(repositoryBody);
        }
        list.sort(Comparator.comparing(ArrivalRepositoryBody::getCInvCode));
        // 详情单的所有总数之和大于数据数量就进行减法计算
        if (bg.compareTo(arrivalRep.getQty()) > 0) {
            ArrivalRepositoryBody one = list.get(0);
            one.setIQuantity(one.getIQuantity().subtract(bg.subtract(arrivalRep.getQty())));
        }
        return list;
    }


    /**
     * 获取 收发类型
     *
     * @param type 类型【收、发】
     * @return 收发类型
     * @throws JsonProcessingException json解析异常
     */
    public static List<QueryInfoVo> getReceiveSendType(Integer type) throws Exception {
        String response = HttpUtil.get(YYConstant.RECEIVE_SEND_TYPE_URL + "/" + type);
        // 判断请求状态
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        if (json.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONArray data = json.getJSONArray("data");
        if (data.isEmpty()) return Collections.emptyList();
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        return om.readValue(data.toString(), new TypeReference<List<QueryInfoVo>>() {
        });
    }

    /**
     * 获取 采购、销售类型
     *
     * @param type 类型【‘cg’,'xs'】
     * @return 类型
     * @throws JsonProcessingException json解析异常
     */
    public static List<QueryInfoVo> getSaleOrPurType(String type) throws Exception {
        String url = "cg".equals(type) ? YYConstant.PUR_TYPE_URL : YYConstant.SALE_TYPE_URL;
        String response = HttpUtil.get(url);
        // 判断请求状态
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        if (json.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONArray data = json.getJSONArray("data");
        if (data.isEmpty()) return Collections.emptyList();
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        return om.readValue(data.toString(), new TypeReference<List<QueryInfoVo>>() {
        });
    }

    /**
     * 获取销售订单
     *
     * @param order 订单
     * @return 销售订单
     * @throws Exception 异常
     */
    public static Map<String, SaleOrderQueryVo> getSaleOrder(String order) throws Exception {
        String response = HttpUtil.post(YYConstant.SALE_ORDER_URL, Collections.singletonMap("order", order));
        // 判断请求状态
        JSONObject orders = JSONUtil.parseObj(response);
        // 判断请求状态
        if (orders.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, orders.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONObject data = orders.getJSONObject("data");
        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据！");
        Map<String, SaleOrderQueryVo> map = new HashMap<>();
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            SaleOrderQueryVo sov = om.readValue(entry.getValue().toString(), new TypeReference<SaleOrderQueryVo>() {
            });
            map.put(entry.getKey(), sov);
        }
        return map;
    }


    /**
     * 获取 储位信息信息
     *
     * @param barCode 储位条码
     * @return 储位
     * @throws JsonProcessingException json解析异常
     */
    public static Goods getGoods(String barCode) throws Exception {
        String response = HttpUtil.get(YYConstant.GOODS_URL, Collections.singletonMap("bar", barCode));
        // 判断请求状态
        JSONObject goods = JSONUtil.parseObj(response);
        // 判断请求状态
        if (goods.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, goods.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONObject data = goods.getJSONObject("data");
        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据");
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        return om.readValue(data.toString(), Goods.class);
    }

    /**
     * 获取 工单及其物料信息
     *
     * @param mocCode 任务令
     * @return 工单信息
     * @throws JsonProcessingException json解析错误
     */
    public static Moco getMocoByCondition(String mocCode) throws Exception {
        Moco moco = new Moco();
        Map<String, Object> map = new HashMap<>();
        map.put("mocCode", mocCode);
        String response = HttpUtil.get(YYConstant.MOCO_URL, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        if (json.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr("msg"));
        // 获取数据
        JSONObject data = json.getJSONObject("data");
        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据！");
        String fuserid = AppContext.getBean(LoginUserRedisService.class).getUser().getFuserid();
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        // 获取工单信息
        JSONObject mocoRders = data.getJSONObject("mocoRders");
        // 获取工单物料信息
        JSONArray mrb = data.getJSONArray("mocoRdersBordyList");
        MocoRders mr = om.readValue(mocoRders.toString(), MocoRders.class);
        Helper.setDefaultAddValue(mr, fuserid);
        mr.setfPreserveFlag(0);
        moco.setMocoRders(mr);
        List<MocoRdersBordy> bordyList = new LinkedList<>();
        for (Object mb : mrb) {
            JSONObject js = JSONUtil.parseObj(mb);
            MocoRdersBordy mocoRdersBordy = om.readValue(js.toString(), MocoRdersBordy.class);
            Helper.setDefaultAddValue(mocoRdersBordy, fuserid);
            bordyList.add(mocoRdersBordy);
        }
        moco.setMocoRdersBordyList(bordyList);
        return moco;
    }

    /**
     * 获取tradeld
     *
     * @return tradeId
     * @throws Exception 异常
     */
    public static String getTradeId() throws Exception {
        Map<String, Object> map = pubMap();
        String response = HttpUtil.get(YYConstant.TRADE_ID_URL, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return json.getJSONObject("trade").getStr("id");
    }

    /**
     * 获取仓库信息
     */
    public static Set<Repository> getU8Repository() throws Exception {
        Map<String, Object> map = pubMap();
        String response = HttpUtil.get(YYConstant.REPOSITORY_URL, map);
        map.put("rows_per_page", 1); // 	取一条数据 目的是为了查询出总条数
        map.put("page_index", 1); // 第1页
        // 判断请求状态(获取总条数)
        JSONObject jsonFirst = JSONUtil.parseObj(response);
        int one = jsonFirst.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (one != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, jsonFirst.getStr(YYConstant.ERR_MSG));
        long row_count = jsonFirst.getLong("row_count");
        map.put("rows_per_page", row_count);
        // 再次发起请求  获取全部仓库信息
        String reResponse = HttpUtil.get(YYConstant.REPOSITORY_URL, map);
        JSONObject json = JSONUtil.parseObj(reResponse);
        int error_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (error_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        // 获取仓库信息
        JSONArray array = json.getJSONArray("warehouse");
        // 数据为空 返回空数据
        if (array.isEmpty()) return Collections.emptySet();
        // 声明一个集合 用来存储仓库信息
        Set<Repository> set = new TreeSet<>(Comparator.comparing(Repository::getCode));
        for (Object o : array)
            set.add(JSONUtil.parseObj(o).toBean(Repository.class));
        return set;
    }

    /**
     * 获取仓库信息
     */
    public static List<Repository> getRepository() throws Exception {
        String response = HttpUtil.get(YYConstant.REPOSITORY_WH);
        // 判断请求状态
        JSONObject goods = JSONUtil.parseObj(response);
        // 判断请求状态
        if (goods.getInt("code") != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, goods.getStr("msg"));
        // 请求失败 抛出请求异常信息
        JSONArray data = goods.getJSONArray("data");
        if (data.isEmpty()) throw new BusinessException(HttpStatus.BAD_REQUEST, "暂无数据");
        return data.stream()
                .map(res -> JSONUtil.toBean((JSONObject) res, Repository.class))
                .collect(Collectors.toList());
    }

    /**
     * 新增一张其他入库单
     *
     * @param params post请求体参数
     * @return 新增其他入库单成功的id
     * @throws Exception 异常
     */
    public static String saveOtherGodownEntry(Map<String, Object> params) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        // 获取交易唯一识别码
        String tradeId = getTradeId();
        map.put("tradeid", tradeId);
        // 同步请求
        map.put("sync", 1);
        StringBuilder url = new StringBuilder(YYConstant.OTHER_GOODS_ENTRY);
        url.append("?");
        for (String key : map.keySet()) url.append(key).append("=").append(map.get(key)).append("&");
        String response = HttpUtil.post(url.substring(0, url.length() - 1), JSONUtil.toJsonStr(params));
        JSONObject json = JSONUtil.parseObj(response);
        // 请求失败 抛出请求异常信息
        if (json.containsKey(YYConstant.ERR_CODE))
            throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return tradeId;
    }

    /**
     * 更新 token
     *
     * @return token
     */
    public static String resetU8token() throws Exception {
        // 获取redis对象
        RedisHelper helper = AppContext.redisHelper();
        // 获取当前登录人的id
        String fuserid = AppContext.getBean(LoginUserRedisService.class).getUser().getFuserid();
        // 拼接key主键
        String key = Helper.keyGe(YYConstant.TOKEN_SUFFIX, fuserid);
        // 删除原来的
        helper.delKey(key);
        // 不存在 获取最新token
        String response = HttpUtil.get(YYConstant.TOKEN_URL, tokenMap());
        // 解析响应字符串
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        JSONObject yyToken = json.getJSONObject("token");
        // 获取token
        String token = yyToken.getStr("id");
        // 获取token的有效时间
        int expiresIn = yyToken.getInt("expiresIn");
        // 将token存入redis 并设置有效时间
        helper.set(key, token, expiresIn - 1800, TimeUnit.SECONDS);
        return token;
    }

    /**
     * 认证获取token
     *
     * @return token对象
     */
    public static String authToken() throws Exception {
        // 获取redis对象
        RedisHelper helper = AppContext.redisHelper();
        // 获取当前登录人的id
        String fuserid = AppContext.getBean(LoginUserRedisService.class).getUser().getFuserid();
        // 拼接key主键
        String key = Helper.keyGe(YYConstant.TOKEN_SUFFIX, fuserid);
        // 从缓存中获取token字符串
        String token = helper.get(key);
        // 存在（没有过期） 直接返回
        if (token != null) return token;
        // 不存在 获取最新token
        String response = HttpUtil.get(YYConstant.TOKEN_URL, tokenMap());
        // 解析响应字符串
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        JSONObject yyToken = json.getJSONObject("token");
        // 获取token
        token = yyToken.getStr("id");
        // 获取token的有效时间
        int expiresIn = yyToken.getInt("expiresIn");
        // 将token存入redis 并设置有效时间
        helper.set(key, token, expiresIn - 3000, TimeUnit.SECONDS);
        return token;
    }

    /**
     * 现存量查询
     *
     * @param params 条件查询
     * @return object
     * @throws Exception 异常
     */
    public static BigDecimal getCurrentStock(Map<String, Object> params) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        params.forEach(map::put);
        String response = HttpUtil.get(YYConstant.CURRENT_STOCK, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return JSONUtil.parseObj(json.getJSONArray("currentstock").get(0)).getBigDecimal("qty");
    }

    /**
     * 现存量时间查询
     *
     * @param map 条件查询
     * @return object
     * @throws Exception 异常
     */
    public static String getCurrentStockDate(Map<String, Object> map) {
        String res = HttpUtil.post(YYConstant.CURRENT_STOCK_DATE, JSONUtil.toJsonStr(map));
        JSONObject json = JSONUtil.parseObj(res);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        return json.getStr("data", null);
    }

    /**
     * 生产领料
     *
     * @param scan 领料单条码
     * @return 领料库存信息
     */
    public static Produce getProduce(String scan) {
        String response = HttpUtil.post(YYConstant.PRODUCE_STOCK, Collections.singletonMap("bar", scan));
        JSONObject json = JSONUtil.parseObj(response);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        JSONArray data = json.getJSONArray("data");
        if (data == null || data.isEmpty()) throw new BusinessException("暂无物料库存信息");
        JSONObject da = data.getJSONObject(0);
        Produce produce = new Produce(da.getStr("invCode"), da.getStr("batch"), da.getBigDecimal("qty"), da.getStr("whCode"));
//        for (int i = 0; i < data.size(); i++) {
//            if (i == 0) continue;
//            JSONObject ds = data.getJSONObject(i);
//            produce.setQty(ds.getBigDecimal("qty"));
//        }
        return produce;
    }

    /**
     * 生产领料单
     *
     * @param scan 生产订单条码
     * @return 领料单信息
     */
    public static List<ProduceInv> getProduceInv(String scan) throws JsonProcessingException {
        Helper.loadLog("生产领料单", "【生产领料单】", JSONUtil.toJsonPrettyStr(Collections.singletonMap("scan", scan)), null, System.currentTimeMillis(), true);
        String response = HttpUtil.post(YYConstant.PRODUCE_INV, Collections.singletonMap("bar", scan));
        JSONObject json = JSONUtil.parseObj(response);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        JSONArray data = json.getJSONArray("data");
        if (data == null || data.isEmpty()) throw new BusinessException("暂无领料数据！");
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        List<ProduceInv> list = new ArrayList<>();
        for (Object datum : data) {
            ProduceInv produceInv = om.readValue(datum.toString(), new TypeReference<ProduceInv>() {
            });
            list.add(produceInv);
        }
        List<ProduceInv> collect = list.stream().sorted(Comparator.comparing(ProduceInv::getInvCode)).collect(Collectors.toList());
        Helper.loadLog("生产领料单", "【生产领料单】", null, JSONUtil.toJsonPrettyStr(json), System.currentTimeMillis(), true);
        return collect;
    }

    /**
     * 根据物料编号获取物料信息
     *
     * @param invCode 物料编号
     * @return 物料集
     * @throws JsonProcessingException
     */
    public static List<InvCode> getInvByInvCode(String invCode) throws JsonProcessingException {
        String response = HttpUtil.post(YYConstant.INV_CODE, Collections.singletonMap("bar", invCode));
        JSONObject json = JSONUtil.parseObj(response);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        JSONArray data = json.getJSONArray("data");
        if (data == null || data.isEmpty()) throw new BusinessException("暂无领料数据！");
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        List<InvCode> list = new ArrayList<>();
        for (Object datum : data) {
            InvCode inv = om.readValue(datum.toString(), new TypeReference<InvCode>() {
            });
            list.add(inv);
        }
        return list;
    }

    /**
     * 根据物料编号获取物料信息
     *
     * @param invCode 物料编号集合
     * @return 物料集
     * @throws JsonProcessingException
     */
    public static List<InvCode> getInvByInvCode(List<String> invCode) throws JsonProcessingException {
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        String response = HttpUtil.post(YYConstant.INV_CODES, om.writeValueAsString(invCode));
        JSONObject json = JSONUtil.parseObj(response);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        JSONArray data = json.getJSONArray("data");
        if (data == null || data.isEmpty()) throw new BusinessException("暂无领料数据！");
        List<InvCode> list = new LinkedList<>();
        for (Object datum : data) {
            InvCode inv = om.readValue(datum.toString(), new TypeReference<InvCode>() {
            });
            list.add(inv);
        }
        return list;
    }

    /**
     * 根据储位编号和名称查看库存是否存在
     *
     * @param code 储位编号
     * @param name 储位名称
     * @return 库存数
     */
    public static Integer findCurrentIsExistsByPositionCodeAndName(String code, String name) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("code", code);
        map.put("name", name);
        String response = HttpUtil.get(YYConstant.POS_CODE_NAME, map);
        JSONObject json = JSONUtil.parseObj(response);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        return json.getInt("data");
    }

    /**
     * 根据物料编号和批号获取库存信息
     *
     * @param invCode 物料编号
     * @param batch   批号
     * @return 库存
     * @throws JsonProcessingException
     */
    public static Map<String, Object> getStockByInvCodeAndBatch(String invCode, String batch) throws JsonProcessingException {
        Map<String, Object> map = new HashMap<>(2);
        map.put("invCode", invCode);
        map.put("batch", batch);
        String response = HttpUtil.post(YYConstant.INV_BATCH_STOCK, map);
        JSONObject json = JSONUtil.parseObj(response);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        return om.readValue(json.getJSONObject("data").toString(), new TypeReference<Map<String, Object>>() {
        });
    }

    /**
     * 获取单张其它出库单
     *
     * @param id 单据编号
     * @return object
     * @throws Exception 异常
     */
    public static List<OutBound> getOtherOutbound(String id) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        map.put("id", id);
        String response = HttpUtil.get(YYConstant.OTHER_GET_OUTBOUND, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        // 获取出库单信息
        JSONObject otherout = json.getJSONObject("otherout");
        String warehousecode = otherout.getStr("warehousecode");
        String warehousename = otherout.getStr("warehousename");
        JSONArray entry = otherout.getJSONArray("entry");
        if (entry.isEmpty()) return Collections.emptyList();
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        List<OutBound> list = new LinkedList<>();
        for (Object o : entry) {
            OutBound outBound = om.readValue(o.toString(), OutBound.class);
            outBound.setWareHouseCode(warehousecode);
            outBound.setWareHouseName(warehousename);
            outBound.setAlreadyQty(new BigDecimal("0"));
            list.add(outBound);
        }
        return list;
    }

    /**
     * 新增一张其它出库单
     *
     * @param params 出库单参数
     * @return tradeid
     * @throws Exception 异常
     */
    public static String addOtherOutbound(Map<String, Object> params) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        // 获取交易唯一识别码
        String tradeId = getTradeId();
        map.put("tradeid", tradeId);
        // 同步请求
        map.put("sync", 1);
        StringBuilder url = new StringBuilder(YYConstant.OTHER_ADD_OUTBOUND);
        url.append("?");
        for (String key : map.keySet()) url.append(key).append("=").append(map.get(key)).append("&");
        String response = HttpUtil.post(url.substring(0, url.length() - 1), JSONUtil.toJsonStr(params));
        JSONObject json = JSONUtil.parseObj(response);
        // 请求失败 抛出请求异常信息
        if (json.containsKey(YYConstant.ERR_CODE))
            throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return tradeId;
    }

    /**
     * 审核一张其它出库单
     *
     * @param params 出库单参数
     * @return 是否审核成功
     * @throws Exception 异常
     */
    public static boolean auditOtherOutbound(Map<String, Object> params) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        // 获取交易唯一识别码
        StringBuilder url = new StringBuilder(YYConstant.OTHER_AUDIT_OUTBOUND);
        url.append("?");
        for (String key : map.keySet()) url.append(key).append("=").append(map.get(key)).append("&");
        String response = HttpUtil.post(url.substring(0, url.length() - 1), JSONUtil.toJsonStr(params));
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return true;
    }

    /**
     * 包装入库
     *
     * @param params 入库参数
     * @return tradeid
     * @throws Exception 异常
     */
    public static String packageWarehouse(Map<String, Object> params) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        // 获取交易唯一识别码
        String tradeId = getTradeId();
        map.put("tradeid", tradeId);
        // 同步请求
        map.put("sync", 1);
        StringBuilder url = new StringBuilder(YYConstant.PACKAGE_WAREHOUSE);
        url.append("?");
        for (String key : map.keySet()) url.append(key).append("=").append(map.get(key)).append("&");
        String response = HttpUtil.post(url.substring(0, url.length() - 1), JSONUtil.toJsonStr(params));
        JSONObject json = JSONUtil.parseObj(response);
        // 请求失败 抛出请求异常信息
        if (json.containsKey(YYConstant.ERR_CODE))
            throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return tradeId;
    }


    /**
     * 获取客户信息
     *
     * @return 客户信息
     * @throws Exception 异常
     */
    public static List<Customer> getCustomer() throws Exception {
        Map<String, Object> map = pubMap();
        map.put("rows_per_page", 2000);
        String response = HttpUtil.get(YYConstant.CUSTOMER, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        // 获取仓库信息
        JSONArray array = json.getJSONArray("customer");
        // 数据为空 返回空数据
        if (array.isEmpty()) return Collections.emptyList();
        // 声明一个集合 用来存储仓库信息
        List<Customer> list = new LinkedList<>();
        for (Object o : array) {
            JSONObject res = JSONUtil.parseObj(o);
            list.add(new Customer(res.getStr("name"), res.getStr("code")));
        }
        return list;
    }

    /**
     * 获取客户信息
     *
     * @return 客户信息
     * @throws Exception 异常
     */
    public static Customer getCustomerByCode(String customerCode) throws Exception {
        Map<String, Object> map = pubMap();
        map.put("id", customerCode);
        String response = HttpUtil.get(YYConstant.CUSTOMER_SINGLE, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        // 获取仓库信息
        JSONObject customer = json.getJSONObject("customer");
        return new Customer(customer.getStr("code"), customer.getStr("name"));
    }

    /**
     * 根据客户名称获取 销售订单列表
     *
     * @param customerCode 客户编码
     * @return 客户订单列表
     * @throws Exception
     */
    public static List<CustomerOrder> getSalesOrderLis(String customerCode) throws Exception {
        Map<String, Object> map = pubMap();
        // 客户名称
        map.put("custcode", customerCode);
        // 状态
        map.put("state", YYConstant.ORDER_STATE);
        String response = HttpUtil.get(YYConstant.SALES_ORDER_LIS, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        // 获取仓库信息
        JSONArray array = json.getJSONArray("saleorderlist");
        // 数据为空 返回空数据
        if (array.isEmpty()) return Collections.emptyList();
        // 声明一个集合 用来存储仓库信息
        List<CustomerOrder> list = new LinkedList<>();
        for (Object o : array) {
            JSONObject res = JSONUtil.parseObj(o);
            list.add(new CustomerOrder(res.getStr("custcode"), // 客户名称
                    res.getStr("cusname"), // 订单编号
                    res.getStr("code"), // 客户编码
                    res.getStr("sendaddress") // 发送地址
            ));
        }
        return list;
    }

    /**
     * 获取销售订单
     *
     * @param orderCode 订单编号
     * @return 销售订单
     * @throws Exception
     */
    public static SalesOrderSave getSalesOrder(String orderCode) throws Exception {
        Map<String, Object> map = pubMap();
        // 订单编号
        map.put("id", orderCode);
        String response = HttpUtil.get(YYConstant.SALES_ORDER, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        // 获取仓库信息
        JSONObject saleorder = json.getJSONObject("saleorder");
        if (saleorder != null) {
            SalesOrderSave salesOrderSave = new SalesOrderSave();
            ObjectMapper mapper = Helper.JACKSON_OBJECT_MAPPER;
            // 单头
            SalesOrderHead salesOrderHead = mapper.readValue(saleorder.toString(), SalesOrderHead.class);
            salesOrderHead.setfOrderCode(orderCode);
            salesOrderSave.setSalesOrderHead(salesOrderHead);
            JSONArray array = saleorder.getJSONArray("entry");
            // 数据为空 返回空数据
            if (array.isEmpty()) return salesOrderSave;
            // 声明一个集合 用来存单身信息
            List<SalesOrderBody> list = new LinkedList<>();
            for (Object o : array)
                list.add(mapper.readValue(JSONUtil.parseObj(o).toString(), SalesOrderBody.class));
            salesOrderSave.setSalesOrderBodyList(list);
            return salesOrderSave;
        }
        return null;
    }

    /**
     * 新增一张发货单
     *
     * @param params 发货单信息
     * @return tradeid
     * @throws Exception 异常
     */
    public static String saveDelivery(Map<String, Object> params) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        // 获取交易唯一识别码
        String tradeId = getTradeId();
        map.put("tradeid", tradeId);
        // 同步请求
        map.put("sync", 1);
        StringBuilder url = new StringBuilder(YYConstant.ADD_DELIVERY);
        url.append("?");
        for (String key : map.keySet()) url.append(key).append("=").append(map.get(key)).append("&");
        String response = HttpUtil.post(url.substring(0, url.length() - 1), JSONUtil.toJsonStr(params));
        JSONObject json = JSONUtil.parseObj(response);
        // 请求失败 抛出请求异常信息
        if (json.containsKey(YYConstant.ERR_CODE))
            throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return tradeId;
    }

    /**
     * 验证是否保存成功
     *
     * @param tradeId tradeId
     * @return tradeid
     * @throws InterruptedException 异常
     */
    public static String saveResult(String tradeId) throws InterruptedException {
        /*
        上述 api 请求返回信息表示建议客户端 3 秒钟后向 https://api.yonyouup.com/result?requestid=158f3f05730711e591c702004c4f4f50 发送 GET 请求获取真正的 api 调用结果，结果格式如下：
            {
              "errcode" : "0",
              "errmsg" : "",
              "id" : "883",
              "tradeid" : "158f3f05730711e591c702004c4f4f50"
            }
         */
        TimeUnit.SECONDS.sleep(3);
        String response = HttpUtil.get(YYConstant.SAVE_RESULT, Collections.singletonMap("requestid", tradeId));
        JSONObject json = JSONUtil.parseObj(response);
        // 请求失败 抛出请求异常信息
        if (json.containsKey(YYConstant.ERR_CODE))
            throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        return tradeId;
    }

    /**
     * 根据存货编码查询库存和仓库信息
     *
     * @param code 存货编码
     * @return 库存-仓库信息
     * @throws Exception 异常
     */
    public static List<GoodsCurrent> getGoodsAndCurrent(String code) throws Exception {
        // 获取公共 请求参数
        Map<String, Object> map = pubMap();
        map.put("rows_per_page", 1); // 	取一条数据 目的是为了查询出总条数
        map.put("page_index", 1); // 第1页
        map.put("invcode_begin", code);
        map.put("invcode_end", code);
        String response = HttpUtil.get(YYConstant.CURRENT_STOCK, map);
        // 判断请求状态
        JSONObject first = JSONUtil.parseObj(response);
        int first_err_code = first.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (first_err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, first.getStr(YYConstant.ERR_MSG));
        map.put("rows_per_page", first.getInt("row_count"));
        response = HttpUtil.get(YYConstant.CURRENT_STOCK, map);
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int err_code = json.getInt(YYConstant.ERR_CODE);
        // 请求失败 抛出请求异常信息
        if (err_code != 0) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr(YYConstant.ERR_MSG));
        JSONArray array = json.getJSONArray("currentstock");
        if (!array.isEmpty()) {
            // 去重仓库名称
            Set<String> set = new HashSet<>();
            List<GoodsCurrent> list = new LinkedList<>();
            int index = 1;
            for (Object o : array) {
                JSONObject j = JSONUtil.parseObj(o);
                BigDecimal qty = j.getBigDecimal("qty");
                if (qty.compareTo(BigDecimal.ONE) > 0) {
                    GoodsCurrent goodsCurrent = new GoodsCurrent();
                    goodsCurrent.setInvCode(j.getStr("invcode"));
                    goodsCurrent.setWhCode(j.getStr("whcode"));
                    goodsCurrent.setInventory(qty);
                    goodsCurrent.setAvailQty(j.getBigDecimal("availqty"));
                    goodsCurrent.setBatch(j.getStr("batch"));
                    goodsCurrent.setRow(index++);
                    list.add(goodsCurrent);
                    set.add(j.getStr("whcode"));
                }
            }
            if (!list.isEmpty()) {
                String post = HttpUtil.post(YYConstant.GOODS_MAP_URL, JSONUtil.toJsonPrettyStr(set));
                json = JSONUtil.parseObj(post);
                // 判断请求状态
                int post_code = json.getInt("code");
                // 请求失败 抛出请求异常信息
                if (post_code != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr("msg"));
                ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
                Map<String, Goods> goodsMap = om.readValue(json.getStr("data"), new TypeReference<Map<String, Goods>>() {
                });
                return list.stream().sorted(Comparator.comparing(GoodsCurrent::getBatch)).peek(data -> data.setInvName(goodsMap.get(data.getWhCode()).getGoodsName())).collect(Collectors.toList());
            }
        }
        throw new BusinessException("暂无数据！");
    }

    /**
     * 根据存货编码查询库存和仓库信息
     *
     * @param code   存货编码
     * @param whCode 仓库编号
     * @return 库存-仓库信息
     */
    public static List<GoodsCurrent> getPositionInfo(String code, String whCode) {
        Map<String, String> params = new HashMap<>(2);
        params.put("invCode", code);
        if (Helper.isNotEmpty(whCode)) params.put("whCode", whCode);
        String response = HttpUtil.post(YYConstant.POSITION_INV_URL, JSONUtil.toJsonStr(params));
        JSONObject json = JSONUtil.parseObj(response);
        // 判断请求状态
        int post_code = json.getInt("code");
        // 请求失败 抛出请求异常信息
        if (post_code != 200) throw new BusinessException(HttpStatus.BAD_REQUEST, json.getStr("msg"));
        JSONArray data = json.getJSONArray("data");
        if (data.isEmpty()) throw new BusinessException("暂无数据！");
        List<GoodsCurrent> list = new LinkedList<>();
        for (int i = 0; i < data.size(); i++) {
            JSONObject meta = (JSONObject) data.get(i);
            GoodsCurrent current = new GoodsCurrent();
            current.setRow(i + 1); // 行数
            current.setAutoId(meta.getStr("autoId")); // 仓库编码
            current.setWhCode(meta.getStr("cWhCode")); // 仓库编码
            current.setInvCode(meta.getStr("cInvCode")); // 存货编码
            current.setPosCode(meta.getStr("cPosCode")); // 货位编码
            current.setInvName(meta.getStr("cPosName")); // 货位名称
            current.setInventory(meta.getBigDecimal("iQuantity")); // 现存数量
            current.setBatch(meta.getStr("cBatch")); // 批号
            current.setdMadeDate(meta.getStr("dMadeDate"));
            current.setVersion(meta.getStr("cFree"));
            list.add(current);
        }
        return list;
    }

    /**
     * 产成品入库单接口
     *
     * @param params 请求参数
     * @return 是否请求成功
     */
    public static String ptsProIn(String params) {
        Map<String, String> map = Collections.singletonMap("data", params);
        Helper.loadLog("【产成品入库单】", JSONUtil.toJsonPrettyStr(params), null, System.currentTimeMillis(), true);
        String data = JSONUtil.parseObj(map).toString();
        String post = HttpUtil.post(YYConstant.PTS_PRO_IN, data);
        JSONObject json = JSONUtil.parseObj(post);
        Helper.loadLog("【产成品入库单】", null, JSONUtil.toJsonPrettyStr(json), System.currentTimeMillis(), true);
        Boolean isSucceed = json.getBool("IsSucceed");
        if (!isSucceed) throw new BusinessException(json.getStr("Err"));
        return "ok";
    }

    /**
     * 采购入库单
     *
     * @param params 请求参数
     * @return 是否请求成功
     */
    public static String ptsPurIn(String params) {
        Map<String, String> map = Collections.singletonMap("data", params);
        Helper.loadLog("【采购入库单】", JSONUtil.toJsonPrettyStr(params), null, System.currentTimeMillis(), true);
        String data = JSONUtil.parseObj(map).toString();
        String post = HttpUtil.post(YYConstant.PTS_PUR_IN, data);
        Helper.loadLog("【采购入库单元数据】", null, post, System.currentTimeMillis(), true);
        Helper.loadLog("【采购入库单】", null, JSONUtil.toJsonPrettyStr(post), System.currentTimeMillis(), true);
        JSONObject json = JSONUtil.parseObj(post);
        Boolean isSucceed = json.getBool("IsSucceed");
        if (!isSucceed) throw new BusinessException(json.getStr("Err"));
        return "ok";
    }

    /**
     * 材料出库单接口
     *
     * @param params 请求参数
     * @return 是否请求成功
     */
    public static String ptsProOut(String params) {
        Map<String, String> map = Collections.singletonMap("data", params);
        Helper.loadLog("【材料出库单】", JSONUtil.toJsonPrettyStr(params), null, System.currentTimeMillis(), true);
        String data = JSONUtil.parseObj(map).toString();
        String post = HttpUtil.post(YYConstant.PTS_PRO_OUT, data);
        JSONObject json = JSONUtil.parseObj(post);
        Helper.loadLog("【材料出库单】", null, JSONUtil.toJsonPrettyStr(json), System.currentTimeMillis(), true);
        Boolean isSucceed = json.getBool("IsSucceed");
        if (!isSucceed) throw new BusinessException(json.getStr("Err"));
        return "ok";
    }

    /**
     * 发货单接口
     *
     * @param params 请求参数
     * @return 是否请求成功
     */
    public static String ptsDispatchList(String params) {
        Map<String, String> map = Collections.singletonMap("data", params);
        Helper.loadLog("【发货单】", JSONUtil.toJsonPrettyStr(params), null, System.currentTimeMillis(), true);
        String data = JSONUtil.parseObj(map).toString();
        String post = HttpUtil.post(YYConstant.PTS_DISPATCH_LIST, data);
        JSONObject json = JSONUtil.parseObj(post);
        Helper.loadLog("【发货单】", null, JSONUtil.toJsonPrettyStr(json), System.currentTimeMillis(), true);
        Boolean isSucceed = json.getBool("IsSucceed");
        if (!isSucceed) throw new BusinessException(json.getStr("Err"));
        return json.getJSONObject("Data").getStr("cCode");
    }

    /**
     * 审核发货单接口
     *
     * @param params 请求参数
     * @return 是否请求成功
     */
    public static Integer ptsDispatchAudit(Map<String, Object> params) {
        String param = JSONUtil.parseObj(params).toString();
        String post = HttpUtil.post(YYConstant.PTS_DISPATCH_AUDIT, param);
        JSONObject json = JSONUtil.parseObj(post);
        Helper.loadLog("【发货单审核】", null, json.toStringPretty(), System.currentTimeMillis(), true);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        return json.getInt("data");
    }

    /**
     * 库存查询接口
     *
     * @param query 库存查询
     * @return 库存查询结果
     */
    public static JsonPage<InventoryExport> getInventory(InventoryQuery query) throws Exception {
        String param = JSONUtil.toJsonStr(query);
        String post = HttpUtil.post(YYConstant.INVENTORY, param);
        JSONObject json = JSONUtil.parseObj(post);
        if (json.getInt("code") != 200) throw new BusinessException(json.getStr("msg"));
        ObjectMapper om = Helper.JACKSON_OBJECT_MAPPER;
        return om.readValue(json.getStr("data"), new TypeReference<JsonPage<InventoryExport>>() {
        });
    }

    /**
     * 格式时间
     *
     * @param bodies 参数
     * @return {@code JSONObject}
     */
    public static JSONArray formatTime(JSONArray bodies) {
        for (Object datum : bodies) {
            JSONObject head = (JSONObject) datum;
            if (head.containsKey("dDate")) {
                String dDate = head.getStr("dDate");
                if (Helper.isNotEmpty(dDate) && dDate.length() > 10) {
                    head.putOpt("dDate", dDate.substring(0, 10));
                }
                if (head.containsKey("Rows")) {
                    for (Object rows : head.getJSONArray("Rows")) {
                        JSONObject row = (JSONObject) rows;
                        if (row.containsKey("dMDate")) {
                            String dMDate = row.getStr("dMDate");
                            if (Helper.isNotEmpty(dMDate) && dMDate.length() > 10) {
                                row.putOpt("dMDate", dMDate.substring(0, 10));
                            }
                        }
                    }
                }
            }
        }
        return bodies;
    }

    /**
     * 格式时间
     *
     * @param map 参数
     * @return {@code JSONObject}
     */
    public static JSONObject formatTime(Map<String, Object> map) {
        JSONObject json = JSONUtil.parseObj(map);
        JSONArray data = json.getJSONArray("data");
        for (Object datum : data) {
            JSONObject head = (JSONObject) datum;
            if (head.containsKey("dDate")) {
                String dDate = head.getStr("dDate");
                if (Helper.isNotEmpty(dDate) && dDate.length() > 10) {
                    head.putOpt("dDate", dDate.substring(0, 10));
                }
                if (head.containsKey("Rows")) {
                    for (Object rows : head.getJSONArray("Rows")) {
                        JSONObject row = (JSONObject) rows;
                        if (row.containsKey("dMDate")) {
                            String dMDate = row.getStr("dMDate");
                            if (Helper.isNotEmpty(dMDate) && dMDate.length() > 10) {
                                row.putOpt("dMDate", dMDate.substring(0, 10));
                            }
                        }
                    }
                }
            }
        }
        return json;
    }

    /**
     * 到货单日期设置
     *
     * @param target 到货单
     */
    public static void setArrivalAccessTime(JSONArray target) {
        target.forEach(obj -> {
            JSONObject ds = (JSONObject) obj;
            ds.forEach((key, value) -> {
                if ("Rows".equals(key)) {
                    String whCode = ds.getStr("cWhCode");
                    String date = ds.getStr("dDate");
                    Map<String, Object> map = new HashMap<>(4);
                    map.put("whCode", whCode);
                    JSONArray arr = JSONUtil.parseArray(value);
                    arr.forEach(data -> {
                        JSONObject da = (JSONObject) data;
                        String invCode = da.getStr("cInvCode");
                        String batch = da.getStr("cBatch");
                        String free = da.getStr("cFree1");
                        map.put("invCode", invCode);
                        map.put("batch", batch);
                        map.put("free", Helper.isEmpty(free) ? null : free);
                        String res = U8Api.getCurrentStockDate(map);
                        // 查到了时间  就直接设置
                        if (Helper.isNotEmpty(res)) {
                            if (res.length() > 10) da.set("dMDate", res.substring(0, 10));
                        } else if (Helper.isEmpty(res) && Helper.isNotEmpty(free)) { // 时间不存在 并且自由项不为空 证明上一次查询带上了自由项
                            // 移除自由项
                            map.remove("free");
                            // 查询
                            res = U8Api.getCurrentStockDate(map);
                            // 如果时间不为空 就重新赋值  否则保持不变
                            if (Helper.isNotEmpty(res) && res.length() > 10) da.set("dMDate", res);
                        } else {
                            da.set("dMDate", date);
                        }
                    });
                }
            });
        });
    }

    /**
     * 到货单日期设置
     *
     * @param target 到货单/出库单
     */
    public static void setAccessTime(JSONArray target) {
        target.forEach(obj -> {
            JSONObject ds = (JSONObject) obj;
            ds.forEach((key, value) -> {
                if ("Rows".equals(key)) {
                    String whCode = ds.getStr("cWhCode");
                    String date = ds.getStr("dDate");
                    Map<String, Object> map = new HashMap<>(4);
                    map.put("whCode", whCode);
                    JSONArray arr = JSONUtil.parseArray(value);
                    arr.forEach(data -> {
                        JSONObject da = (JSONObject) data;
                        String invCode = da.getStr("cInvCode");
                        String batch = da.getStr("cBatch");
                        String free = da.getStr("cFree1");
                        map.put("invCode", invCode);
                        map.put("batch", batch);
                        // 确保版本不为bull
                        if (Helper.isEmpty(free)) {
                            da.set("cFree1", "");
                        }
                        map.put("free", Helper.isEmpty(free) ? "" : free);
                        String res = U8Api.getCurrentStockDate(map);
                        // 查到了时间  就直接设置
                        if (Helper.isNotEmpty(res)) {
                            if (res.length() > 10) da.set("dMDate", res.substring(0, 10));
                        } else if (Helper.isEmpty(res) && Helper.isNotEmpty(free)) { // 时间不存在 并且自由项不为空 证明上一次查询带上了自由项
                            // 移除自由项
                            map.remove("free");
                            // 查询
                            res = U8Api.getCurrentStockDate(map);
                            // 如果时间不为空 就重新赋值  否则保持不变
                            if (Helper.isNotEmpty(res) && res.length() > 10) da.set("dMDate", res);
                        } else da.set("dMDate", date);
                    });
                }
            });
        });
    }

    /**
     * 到货单日期设置
     *
     * @param target 到货单/出库单
     */
    public static void setAccessTimes(JSONArray target) {
        target.forEach(obj -> {
            JSONObject ds = (JSONObject) obj;
            ds.forEach((key, value) -> {
                if ("Rows".equals(key)) {
                    JSONArray arr = JSONUtil.parseArray(value);
                    arr.forEach(data -> {
                        JSONObject da = (JSONObject) data;
                        String free = da.getStr("cFree1");
                        // 确保版本不为bull
                        if (Helper.isEmpty(free)) {
                            da.set("cFree1", "");
                        }
                        Object date = da.get("dMadeDate");
                        if (date != null) {
                            if (!((String) date).isEmpty()) {
                                da.set("dMadeDate", date.toString().substring(0, 10));
                            }
                        }
                    });
                }
            });
        });
    }
}